/**
* @file ModuleBase.h
* @author
* @brief 用于模块衍生的基类
* @version 1.0
* @date 2020-08-21
*
* @copyright Copyright (c) 2020
*
*/

#pragma once

#include <rclcpp/rclcpp.hpp>
#include <boost/signals2/signal.hpp>
#include <boost/thread.hpp>
#include <atomic>
#include "data_struct/base/TimeWorkBase/EventBase/OccurFailure.hpp"
#include "data_struct/base/TimeWorkBase/EventBase/OccurRegister.h"
#include "data_struct/base/TimeWorkBase/Cloners/FunctionCloner.hpp"
#include "modules/AssistModule/LogModule.h"
#include "data_struct/base/EventBase.h"

namespace behavior_controller
{

class ModuleBase : public std::enable_shared_from_this<ModuleBase>
{
public:
    ModuleBase() : is_installed_(false) {}

    virtual ~ModuleBase() = default;

    void Install();

    void Uninstall();

    void Start();

    void set_name(std::string name) { name_ = name; }

    const std::string &name() { return name_; }

private:
    virtual void InstallModule() = 0;

    virtual void StartModule() {}

    virtual void PrepareRemove() = 0;

    std::string name_;
    bool is_installed_;
};

class ClonerBase : public ModuleBase
{
public:
    typedef boost::signals2::signal<void()> SigType;

    virtual ~ClonerBase() = default;

    virtual void PrepareRemove();

    virtual void Initialize() {}

    virtual void Work() = 0;

    virtual void Clear() = 0;

private:
    void InstallModule();

    void StartModule();

    std::shared_ptr<boost::thread> work_thread_ptr_;
};

template<typename Derived>
class ModuleCloner : public ClonerBase
{
public:
    ModuleCloner() : signal_ready_(false) {}

    virtual ~ModuleCloner() = default;

    template<typename Ftr, typename Evt>
    void InstallFunctor(
            std::shared_ptr<Ftr> &&functor_ptr,
            time::SteadyClock::Duration timeout = time::SteadyClock::Duration::zero())
    {
        auto handler = [this, functor_ptr](const std::shared_ptr<Evt> &evt_ptr)
        {
            CallFunctor<Ftr, Evt>(functor_ptr, evt_ptr);
        };

        occur_failure_.RegisterEventHandler<Evt, Ftr>(handler, timeout);
    }

    template<typename Evt>
    void InstallFunction(
            std::function<void(Derived *, const Evt &)> &&func,
            time::SteadyClock::Duration timeout = time::SteadyClock::Duration::zero())
    {
        InstallFunctor<FunctionEventFunctor<Derived, Evt>, Evt>(
                std::make_shared<FunctionEventFunctor<Derived, Evt>>(
                        std::forward<std::function<void(Derived *, const Evt &)>>(func)),
                timeout);
    }

    template<typename Evt>
    void InstallFunction(
            std::function<void(Derived *)> &&func,
            time::SteadyClock::Duration timeout = time::SteadyClock::Duration::zero())
    {
        InstallFunctor<FunctionCloner<Derived, Evt>, Evt>(
                std::make_shared<FunctionCloner<Derived, Evt>>(
                        std::forward<std::function<void(Derived *)>>(func)),
                timeout);
    }

    std::shared_ptr<Derived> SharedFromThis()
    {
        return std::static_pointer_cast<Derived>(shared_from_this());
    }

    //private:
    template<typename Ftr, typename Evt>
    void CallFunctor(const std::shared_ptr<Evt> &evt_ptr)
    {
        Ftr().Call(*((Derived *) this), evt_ptr);
    }

    template<typename Ftr, typename Evt>
    void CallFunctor(const std::shared_ptr<Ftr> &functor_ptr,
                     const std::shared_ptr<Evt> &evt_ptr)
    {
        functor_ptr->Call(*((Derived *) this), evt_ptr);
    }

    //protected:
    virtual void Initialize() override
    {
        AddHealthCheckHandler();
        InstallFunctors();
    }

    void Work() override
    {
        while (rclcpp::ok())
        {
            try
            {
                occur_failure_.HandleEvents();
                boost::this_thread::interruption_point();
            }
            catch (const boost::thread_interrupted &e)
            {
                throw e;
            }
            catch (const std::exception &e)
            {
                std::cout << "ModuleBase: std::exception" << std::endl;
                throw e;
            }
        }
    }

    void Clear() override { occur_failure_.Clear(); }

    virtual void InstallFunctors() = 0;

private:
    void AddHealthCheckHandler()
    {
        InstallFunction<occur::Heartbeat>(
                &ModuleCloner::SendHealthCheckCallback);
    }

    void SendHealthCheckCallback()
    {
        occur::HeartbeatCallback::Send(name());
    }

    bool signal_ready_;
    boost::mutex signal_mutex_;
    boost::condition_variable signal_cond_;
    std::vector<std::shared_ptr<occur::OccurRegister>> register_ptrs_;
    occur::OccurFailure occur_failure_;
};

} // namespace behavior_controller
